#include "EquationSolver.h"
#include <iostream>
#include <string>
#include <stdlib.h>
#include <algorithm>
#include <cmath>
using namespace std;

double delta=numeric_limits<double>::epsilon();


//function of Problem B_1

class B_1 :public Function
{
 public:
  double operator()(double _x)
  {
    return pow(_x,-1)-tan(_x);
  }
  double diff(double _x)
  {
    double eps=0.00001;
    double _x1=_x+eps,_x2=_x-eps;
    double result = ((pow(_x1,-1)-tan(_x1))-(pow(_x2,-1)-tan(_x2)))/(2*eps);
    return result;
  }
};

//function of Problem B_2

class B_2 : public Function
{
 public:
  double operator()(double _x)
  {
    return pow(_x,-1)-pow(2,_x);
  }
  double diff(double _x)
  {
    double eps=0.00001;
    double _x1=_x+eps,_x2=_x-eps;
    double result = ((pow(_x1,-1)-pow(2,_x1))-(pow(_x2,-1)-pow(2,_x2)))/(2*eps);
    return result;
  }
};


//function of Problem B_3

class B_3 :public Function
{
 public:
  double operator()(double _x)
  {
    return pow(2,-_x)+exp(_x)+2*cos(_x)-6;
  }
  double diff(double _x)
  {
     double eps=0.00001;
    double _x1=_x+eps,_x2=_x-eps;
    double result = ((pow(2,-_x1)+exp(_x1)+2*cos(_x1)-6)-(pow(2,-_x2)+exp(_x2)+2*cos(_x2)-6))/(2*eps);
    return result;
  }
};


//function of Problem B_4

class B_4 :public Function
{
 public:
  double operator()(double _x)
  {
    return (pow(_x,3)+4*pow(_x,2)+3*_x+5)/(2*pow(_x,3)-9*pow(_x,2)+18*_x-2);
  }
  double diff(double _x)
  {
    double eps=0.00001;
    double _x1=_x+eps,_x2=_x-eps;
    double result = (((pow(_x1,3)+4*pow(_x1,2)+3*_x1+5)/(2*pow(_x1,3)-9*pow(_x1,2)+18*_x1-2))-((pow(_x2,3)+4*pow(_x2,2)+3*_x2+5)/(2*pow(_x2,3)-9*pow(_x2,2)+18*_x2-2)))/(2*eps);
    return result;
  }
};


//function of Problem C

class C :public Function
{
 public:
  double operator()(double _x)
  {
    return _x-tan(_x);
  }
  double diff(double _x)
  {
    double eps=0.00001;
    double _x1=_x+eps,_x2=_x-eps;
    double result = ((_x1-tan(_x1))-(_x2-tan(_x2)))/(2*eps);
    return result;
  }
};

//function of Problem D_1

class D_1 :public Function
{
 public:
  double operator()(double _x)
  {
    return sin(_x/2)-1;
  }
  double diff(double _x)
  {
    return 0;
  }
};

//function of Problem D_2

class D_2 :public Function
{
 public:
  double operator()(double _x)
  {
    return exp(_x)-tan(_x);
  }
  double diff(double _x)
  {
    return 0;
  }
};

//function of Problem D_3

class D_3 :public Function
{
 public:
  double operator()(double _x)
  {
    return pow(_x,3)-12*pow(_x,2)+3*_x+1;
  }
  double diff(double _x)
  {
    return 0;
  }
};

//function of Problem E

class E :public Function
{
 public:
  double operator()(double _x)
  {
    return 10*(0.5*M_PI-asin(1-_x)-(1-_x)*pow((1-(1-_x)*(1-_x)),1/2))-12.4;
  }
  double diff(double _x)
  {
    double eps=0.00001;
    double _x1=_x+eps,_x2=_x-eps;
    double result = ((10*(0.5*M_PI-asin(1-_x1)-(1-_x1)*pow((1-(1-_x1)*(1-_x1)),1/2))-12.4)-(10*(0.5*M_PI-asin(1-_x2)-(1-_x2)*pow((1-(1-_x2)*(1-_x2)),1/2))-12.4))/(2*eps);
    return result;
  }
};

//function of Problem F_a

class F_1 :public Function
{
 public:
  double operator()(double _x)
  {
    return 89*sin((11.5*M_PI)/180)*sin(_x)*cos(_x)
      +89*cos((11.5*M_PI)/180)*sin(_x)*sin(_x)
      -((49+0.5*55)*sin((11.5*M_PI)/180)-0.5*55*tan((11.5*M_PI)/180))*cos(_x)
      -((49+0.5*55)*cos((11.5*M_PI)/180)-0.5*55)*sin(_x);
  }
  double diff(double _x)
  {
    double eps=0.00001;
    double _x1=_x+eps,_x2=_x-eps;
    double result =
      ((89*sin((11.5*M_PI)/180)*sin(_x1)*cos(_x1)
      +89*cos((11.5*M_PI)/180)*sin(_x1)*sin(_x1)
      -((49+0.5*55)*sin((11.5*M_PI)/180)-0.5*55*tan((11.5*M_PI)/180))*cos(_x1)
      -((49+0.5*55)*cos((11.5*M_PI)/180)-0.5*55)*sin(_x1))
      -(89*sin((11.5*M_PI)/180)*sin(_x2)*cos(_x2)
      +89*cos((11.5*M_PI)/180)*sin(_x2)*sin(_x2)
      -((49+0.5*55)*sin((11.5*M_PI)/180)-0.5*55*tan((11.5*M_PI)/180))*cos(_x2)
	-((49+0.5*55)*cos((11.5*M_PI)/180)-0.5*55)*sin(_x2)))/(2*eps);
    return result;
  }
};


//function of Problem F_b

class F_2 :public Function
{
 public:
  double operator()(double _x)
  {
    return 89*sin((11.5*M_PI)/180)*sin(_x)*cos(_x)
      +89*cos((11.5*M_PI)/180)*sin(_x)*sin(_x)
      -((49+0.5*30)*sin((11.5*M_PI)/180)-0.5*30*tan((11.5*M_PI)/180))*cos(_x)
      -((49+0.5*30)*cos((11.5*M_PI)/180)-0.5*30)*sin(_x);
  }
  double diff(double _x)
  {
    double eps=0.00001;
    double _x1=_x+eps,_x2=_x-eps;
    double result =
      ((89*sin((11.5*M_PI)/180)*sin(_x1)*cos(_x1)
      +89*cos((11.5*M_PI)/180)*sin(_x1)*sin(_x1)
      -((49+0.5*30)*sin((11.5*M_PI)/180)-0.5*30*tan((11.5*M_PI)/180))*cos(_x1)
      -((49+0.5*30)*cos((11.5*M_PI)/180)-0.5*30)*sin(_x1))
      -(89*sin((11.5*M_PI)/180)*sin(_x2)*cos(_x2)
      +89*cos((11.5*M_PI)/180)*sin(_x2)*sin(_x2)
      -((49+0.5*30)*sin((11.5*M_PI)/180)-0.5*30*tan((11.5*M_PI)/180))*cos(_x2)
	-((49+0.5*30)*cos((11.5*M_PI)/180)-0.5*30)*sin(_x2)))/(2*eps);
    return result;
  }
};




int main() {

  cout << "----- problem B ----- " << endl;

  Bisection bispb1(0,M_PI/2,delta,100000, new B_1);
  B_1 f1;
  cout << "Answer of problem B_1 is " << bispb1.solve() << " f(x*)= "<< f1(bispb1.solve()) << endl;

  Bisection bispb2(0,1,delta,100000, new B_2);
  B_2 f2;
  cout << "Answer of problem B_2 is " << bispb2.solve()<< " f(x*)= "<< f2(bispb2.solve())  << endl;

  Bisection bispb3(1,3,delta,100000, new B_3);
  B_3 f3;
  cout << "Answer of problem B_3 is " << bispb3.solve()<< " f(x*)= "<< f3(bispb3.solve())  << endl;

  Bisection bispb4(0,4,delta,100000, new B_4);
  B_4 f4;
  cout << "Answer of problem B_4 is " << bispb4.solve()<< " f(x*)= "<< f4(bispb4.solve())  << endl;

  cout << "----- problem C ----- " << endl;

  Newton newpb1(4.5,100000, new C);
  Newton newpb2(7.7,100000, new C);
  C f5;
  C f6;
  cout << "Answer of problem C is " << newpb1.solve() << " and " << newpb2.solve() << endl;
  cout << "f(x1*)= " << f5(newpb1.solve()) << " and " << "f(x2*)= "<<f6( newpb2.solve()) << endl;

  cout << "----- problem D ----- " << endl;

  Secant secpb1(0,M_PI/2,1e-10,1000, new D_1);
  D_1 f7;
  cout << "Answer of problem D_1 is " << secpb1.solve() << " f(x*)= "<< f7(secpb1.solve()) << endl;

  Secant secpb2(1,1.4,1e-10,1000, new D_2);
  D_2 f8;
  cout << "Answer of problem D_2 is " << secpb2.solve() << " f(x*)= "<< f8(secpb2.solve()) << endl;

  Secant secpb3(0,-0.5,1e-10,1000, new D_3);
  D_3 f9;
  cout << "Answer of problem D_3 is " << secpb3.solve() << " f(x*)= "<< f9(secpb3.solve()) << endl;

  Secant secpb11(0,M_PI,1e-10,1000, new D_1);
  D_1 f10;
  cout << "Answer of problem D_1 with initial values 0 and pi is " << secpb11.solve() << " f(x*)= "<< f10(secpb11.solve()) << endl;

  Secant secpb21(1,2,1e-10,1000, new D_2);
  D_2 f11;
  cout << "Answer of problem D_2 with initial values 1 and 2 is " << secpb21.solve() << " f(x*)= "<< f11(secpb21.solve()) << endl;

  Secant secpb31(0,3,1e-10,1000, new D_3);
  D_3 f12;
  cout << "Answer of problem D_3 with initial values 0 and 3 is " << secpb31.solve() << " f(x*)= "<< f12(secpb31.solve()) << endl;

  cout << "----- problem E ----- " << endl;

  Bisection bispb5(0,1,1e-2,1000, new E);
  E f13;
  cout << "Answer of problem E by Bisection method is " << bispb5.solve() << " f(x*)= "<< f13(bispb5.solve()) <<  endl;

  Newton newpb3(0.5,1000, new E);
  E f14;
  cout << "Answer of problem E by Newton method is " << newpb3.solve() << " f(x*)= "<< f14(newpb3.solve()) <<   endl;

  Secant secpb4(0,1,1e-2,1000, new E);
  E f15;
  cout << "Answer of problem E by Secant method is " << secpb4.solve() <<  " f(x*)= "<< f15(secpb4.solve()) <<  endl;

  cout << "----- problem F ----- " << endl;

  Newton newpb4((33*M_PI)/180,1000, new F_1);
  F_1 f16;
  cout << "Answer of problem F_a is " << newpb4.solve()*180/M_PI << " degrees" << " f(x*)= "<< f16(newpb4.solve()) <<    endl;

  Newton newpb5((33*M_PI)/180,1000, new F_2);
  F_2 f17;
  cout << "Answer of problem F_b is " << newpb5.solve()*180/M_PI << " degrees" <<  " f(x*)= "<< f17(newpb5.solve()) <<   endl;

  Secant secpb5(0,(90*M_PI)/180,1e-10,1000, new F_1);
  F_1 f18;
  cout << "Answer of problem F_a by Secant method is " << secpb5.solve()*180/M_PI << " degrees" <<   " f(x*)= "<< f18(secpb5.solve()) <<  endl;

  
}
